﻿using System;
using Quartz;
using Quartz.Impl;
using System.Collections.Specialized;
using Quartz.Impl.Triggers;
using DataProcess.Core.Quartz.Listener;
using DataProcess.Core.Quartz.Jobs;

namespace DataProcess.Core.Quartz
{
    public class QuartzHelper
    {
        NameValueCollection properties = new NameValueCollection();
        ISchedulerFactory factory;
        private IScheduler Scheduler;

        public QuartzHelper(string port = "555")
        {
            properties["quartz.scheduler.instanceName"] = "多任务管理平台";
            // 设置线程池
            properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz";
            properties["quartz.threadPool.threadCount"] = "30";
            properties["quartz.threadPool.threadPriority"] = "Normal";

            factory = new StdSchedulerFactory(properties);
            if (Scheduler != null)
            {
                Scheduler.Shutdown();
            }
#if NET40
            Scheduler = factory.GetScheduler();
#elif NET48
            Scheduler = factory.GetScheduler().Result;
#elif NETSTANDARD2_1
            Scheduler = factory.GetScheduler().Result;
#endif
            AddListener();
        }

        void AddListener(bool addJob = true, bool addTrigger = true, bool addScheduler = true)
        {
            if (addJob)
            {
                //添加任务监听
                JobListener jobListener = new JobListener();
                Scheduler.ListenerManager.AddJobListener(jobListener);
            }

            if (addTrigger)
            {
                //添加Trigger监听
                TriggerListener triggerListener = new TriggerListener();
                Scheduler.ListenerManager.AddTriggerListener(triggerListener);
            }

            if (addScheduler)
            {
                //添加scheduler监听
                SchedulerListener schedulerListener = new SchedulerListener();
                Scheduler.ListenerManager.AddSchedulerListener(schedulerListener);
            }
        }

        /// <summary>
        /// 时间间隔执行任务
        /// </summary>
        /// <typeparam name="T">任务类，必须实现IJob接口</typeparam>
        /// <param name="seconds">时间间隔(单位：秒)</param>
        public void AddJobTriggerInterval<T>(T t, int seconds) where T : BaseJob
        {
            IJobDetail job = JobBuilder.Create<T>()
                .WithIdentity(typeof(T).Name)
                .Build();

            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity(typeof(T).Name)
                .StartNow()
                .WithSimpleSchedule(x => x.WithIntervalInSeconds(seconds).RepeatForever())
                .Build();


#if NET40
            if (!Scheduler.CheckExists(job.Key) && !Scheduler.CheckExists(trigger.Key))
            {
                Scheduler.ScheduleJob(job, trigger);
            }
#elif NET48
            if (!Scheduler.CheckExists(job.Key).Result && !Scheduler.CheckExists(trigger.Key).Result)
            {
                Scheduler.ScheduleJob(job, trigger);
            }
#elif NETSTANDARD2_1
            if (!Scheduler.CheckExists(job.Key).Result && !Scheduler.CheckExists(trigger.Key).Result)
            {
                Scheduler.ScheduleJob(job, trigger);
            }
#endif
        }

        public void DeleteJob<T>() where T : BaseJob
        {
            string key = typeof(T).Name;
            DeleteJob(new TriggerKey(key), new JobKey(key));
        }

        /// <summary>
        /// 移除一个任务
        /// </summary>
        /// <param name="jobName"></param>
        public void DeleteJob(TriggerKey triggerKey, JobKey jobKey)
        {
            //停止触发器
            Scheduler.PauseTrigger(triggerKey);
            //移除触发器
            Scheduler.UnscheduleJob(triggerKey);
            //删除任务
            Scheduler.DeleteJob(jobKey);
        }

        /// <summary>
        /// 更改指定Job的运行间隔
        /// </summary>
        /// <typeparam name="T">Job类型</typeparam>
        /// <param name="eepeatInterval">重复间隔（秒）</param>

        public void ModifyTriggerInterval<T>(int eepeatInterval) where T : BaseJob
        {
            string key = typeof(T).Name;
            var trigger = Scheduler.GetTrigger(new TriggerKey(key));
            var jobDetail = Scheduler.GetJobDetail(new JobKey(key));
#if NET40
            ModifyTriggerInterval(trigger, jobDetail, eepeatInterval);
#elif NET48
            ModifyTriggerInterval(trigger.Result, jobDetail.Result, eepeatInterval);
#elif NETSTANDARD2_1
            ModifyTriggerInterval(trigger.Result, jobDetail.Result, eepeatInterval);
#endif
        }

        /// <summary>
        /// 更改指定Job的运行间隔
        /// </summary>
        /// <param name="trigger"></param>
        /// <param name="jobDetail"></param>
        /// <param name="seconds"></param>
        public void ModifyTriggerInterval(ITrigger trigger, IJobDetail jobDetail, int seconds)
        {
            if (trigger != null)
            {
                SimpleTriggerImpl st = (SimpleTriggerImpl)trigger;
                st.RepeatInterval = new TimeSpan(0, 0, seconds);
                Scheduler.DeleteJob(jobDetail.Key);
                Scheduler.ScheduleJob(jobDetail, st);
            }
        }

        /// <summary>
        /// 指定时间执行任务
        /// quartz中的cron表达式使用如 "/5 * * ? * * *"  这样的7位表达式，最后一位年非必选。
        /// 字段名                     允许的值                允许的特殊字符
        /// Seconds                     0-59	                , - * /
        /// Minutes                     0-59	                , - * /
        /// Hours                       0-23	                , - * /
        /// Day of month                1-31	                , - * ? / L W
        /// Month                   1-12 or JAN-DEC             , - * /
        /// Day of week	             1-7 or SUN-SAT             , - * ? / L #
        /// Year                     空, 1970-2099	            , - * /      
        ///       
        /// 特殊字符	解释
        /// ,	        或的意思。例：分钟位 5,10  即第5分钟或10分都触发。 
        /// /	        a/b。 a：代表起始时间，b频率时间。 例； 分钟位  3/5，  从第三分钟开始，每5分钟执行一次。
        /// *	        频率。 即每一次波动。    例；分钟位* 即表示每分钟 
        /// -	        区间。  例： 分钟位   5-10 即5到10分期间。 
        /// ?	        任意值 。   即每一次波动。只能用在DayofMonth和DayofWeek，二者冲突。指定一个另一个一个要用?
        /// L           表示最后。 只能用在DayofMonth和DayofWeek，4L即最后一个星期三
        /// W           工作日。  表示最后。 只能用在DayofWeek
        /// #	        4#2。 只能用DayofMonth。 某月的第二个星期三  
        /// 
        /// 实例介绍
        ///"0 0 10,14,16 * * ?"    每天10点，14点，16点 触发。
        ///"0 0/5 14,18 * * ?"    每天14点或18点中，每5分钟触发 。
        ///"0 4/15 14-18 * * ?"       每天14点到18点期间,  从第四分钟触发，每15分钟一次。
        ///"0 15 10 ? * 6L"        每月的最后一个星期五上午10:15触发。
        ///
        /// </summary>
        /// <typeparam name="T">任务类，必须实现IJob接口</typeparam>
        /// <param name="cronExpression">cron表达式，即指定时间点的表达式</param>
        /*public void AddJobTriggerByCron<T>(string cronExpression) where T : IJob
        {

            IJobDetail job = JobBuilder.Create<T>().Build();

            ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create()
                .WithCronSchedule(cronExpression)
                .Build();

            scheduler.ScheduleJob(job, trigger);
        }*/
        /// <summary>
        /// 开始调度任务
        /// </summary>
        public void Start()
        {
            if (!Scheduler.IsStarted)
            {
                Scheduler.Start();
            }
        }

        /// <summary>
        /// 停止调度任务
        /// </summary>
        public void ShutDown()
        {
            if (!Scheduler.IsShutdown)
            {
                Scheduler.Shutdown();
            }
        }

        public void PauseAll()
        {
            Scheduler.PauseAll();
        }

        public void ResumeAll()
        {
            Scheduler.ResumeAll();
        }

        public void PauseJob(JobKey jobKey)
        {
            Scheduler.PauseJob(jobKey);
        }

        public void ResumeJob(JobKey jobKey)
        {
            Scheduler.ResumeJob(jobKey);
        }

        public void PauseTrigger(TriggerKey triggerKey)
        {
            Scheduler.PauseTrigger(triggerKey);
        }
        public void ResumeTrigger(TriggerKey triggerKey)
        {
            Scheduler.ResumeTrigger(triggerKey);
        }

        public IJobDetail GetJobDetail(JobKey jobKey)
        {
#if NET40
            return Scheduler.GetJobDetail(jobKey);
#elif NET48
            return Scheduler.GetJobDetail(jobKey).Result;
#elif NETSTANDARD2_1
            return Scheduler.GetJobDetail(jobKey).Result;
#endif
        }

        public ITrigger GetTrigger(TriggerKey triggerKey)
        {
#if NET40
            return Scheduler.GetTrigger(triggerKey);
#elif NET48
            return Scheduler.GetTrigger(triggerKey).Result;
#elif NETSTANDARD2_1
            return Scheduler.GetTrigger(triggerKey).Result;
#endif
        }

        /// <summary>
        /// 触发一次job
        /// </summary>
        /// <param name="jobKey"></param>
        public void TriggerJob(JobKey jobKey)
        {
            Scheduler.TriggerJob(jobKey);
        }
    }
}
